
#pragma once

#ifndef _fmbFn
#define _fmbFn

#include "fmbTL.h"
#include "fmbPtr.h"

namespace fm {
  namespace base {

/// <summary>
///   Template with implementation for functor.
///   This is the base for classes which are puttet into Fn.
///   Any Fn calling is realised through the class which is inherited from this.
/// </summary>
template <typename TRet, class TArgList>
class FnImpl;

template <typename TRet>
class FnImpl<TRet, TL_0> {
public:
  virtual TRet operator()() = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1>
class FnImpl<TRet, TL_1(T1) > {
public:
  virtual TRet operator()(T1 t1) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2>
class FnImpl<TRet, TL_2(T1, T2) > {
public:
  virtual TRet operator()(T1 t1, T2 t2) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3>
class FnImpl<TRet, TL_3(T1, T2, T3) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4>
class FnImpl<TRet, TL_4(T1, T2, T3, T4) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4, typename T5>
class FnImpl<TRet, TL_5(T1, T2, T3, T4, T5) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
class FnImpl<TRet, TL_6(T1, T2, T3, T4, T5, T6) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
class FnImpl<TRet, TL_7(T1, T2, T3, T4, T5, T6, T7) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7,
    typename T8>
class FnImpl<TRet, TL_8(T1, T2, T3, T4, T5, T6, T7, T8) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7,
    typename T8, typename T9>
class FnImpl<TRet, TL_9(T1, T2, T3, T4, T5, T6, T7, T8, T9) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7,
    typename T8, typename T9, typename T10>
class FnImpl<TRet, TL_10(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7,
    typename T8, typename T9, typename T10, typename T11>
class FnImpl<TRet, TL_11(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10,
      T11 t11) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7,
    typename T8, typename T9, typename T10, typename T11, typename T12>
class FnImpl<TRet, TL_12(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10,
      T11 t11, T12 t12) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7,
    typename T8, typename T9, typename T10, typename T11, typename T12, typename T13>
class FnImpl<TRet, TL_13(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10,
      T11 t11, T12 t12, T13 t13) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7,
    typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14>
class FnImpl<TRet, TL_14(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10,
      T11 t11, T12 t12, T13 t13, T14 t14) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

template <typename TRet, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7,
    typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
class FnImpl<TRet, TL_15(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) > {
public:
  virtual TRet operator()(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10,
      T11 t11, T12 t12, T13 t13, T14 t14, T15 t15) = 0;
  virtual ~FnImpl() {}
  virtual FnImpl* clone() = 0;
};

/// <summary>
///   This is handler which implements FnImpl.
///   This handler handles functors and standard functions.
/// </summary>
template <class ParentFn, class Fun>
class FnHandler : public FnImpl<typename ParentFn::ResultType, typename ParentFn::ArgTypeList> {
public:
  typedef typename ParentFn::ResultType ResultType;
  typedef typename ParentFn::ArgTypeList ArgTypeList;
public:
  typedef typename TLAtNonStrict<ArgTypeList, 0, EmptyType>::Type P0;
  typedef typename TLAtNonStrict<ArgTypeList, 1, EmptyType>::Type P1;
  typedef typename TLAtNonStrict<ArgTypeList, 2, EmptyType>::Type P2;
  typedef typename TLAtNonStrict<ArgTypeList, 3, EmptyType>::Type P3;
  typedef typename TLAtNonStrict<ArgTypeList, 4, EmptyType>::Type P4;
  typedef typename TLAtNonStrict<ArgTypeList, 5, EmptyType>::Type P5;
  typedef typename TLAtNonStrict<ArgTypeList, 6, EmptyType>::Type P6;
  typedef typename TLAtNonStrict<ArgTypeList, 7, EmptyType>::Type P7;
  typedef typename TLAtNonStrict<ArgTypeList, 8, EmptyType>::Type P8;
  typedef typename TLAtNonStrict<ArgTypeList, 9, EmptyType>::Type P9;
  typedef typename TLAtNonStrict<ArgTypeList, 10, EmptyType>::Type P10;
  typedef typename TLAtNonStrict<ArgTypeList, 11, EmptyType>::Type P11;
  typedef typename TLAtNonStrict<ArgTypeList, 12, EmptyType>::Type P12;
  typedef typename TLAtNonStrict<ArgTypeList, 13, EmptyType>::Type P13;
  typedef typename TLAtNonStrict<ArgTypeList, 14, EmptyType>::Type P14;

private:
  Fun m_fun;

public:
  FnHandler(const Fun& fun) : m_fun(fun) {}
  virtual ~FnHandler() {}
  virtual FnImpl<ResultType, ArgTypeList>* clone() { return new FnHandler(m_fun); }

  inline ResultType operator()() { return m_fun(); }
  inline ResultType operator()(P0 p0) { return m_fun(p0); }
  inline ResultType operator()(P0 p0, P1 p1) { return m_fun(p0, p1); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2) { return m_fun(p0, p1, p2); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3) { return m_fun(p0, p1, p2, p3); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4) { return m_fun(p0, p1, p2, p3, p4); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { return m_fun(p0, p1, p2, p3, p4, p5); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { return m_fun(p0, p1, p2, p3, p4, p5, p6); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
    return m_fun(p0, p1, p2, p3, p4, p5, p6, p7);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
    return m_fun(p0, p1, p2, p3, p4, p5, p6, p7, p8);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) {
    return m_fun(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10) {
    return m_fun(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11) {
    return m_fun(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11, P12 p12) {
    return m_fun(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11, P12 p12, P13 p13) {
    return m_fun(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11, P12 p12, P13 p13, P14 p14) {
    return m_fun(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14);
  }

};

/// <summary>
///   This is handler which implements FnImpl.
///   This handler handles member functions of objects.
///   Class types are pointer to the object and pointer to the member function.
/// </summary>
template <class ParentFn, typename ObjPtr, typename MemFnPtr>
class MemFnHandler : public FnImpl<typename ParentFn::ResultType, typename ParentFn::ArgTypeList> {
public:
  typedef typename ParentFn::ResultType ResultType;
  typedef typename ParentFn::ArgTypeList ArgTypeList;
public:
  typedef typename TLAtNonStrict<ArgTypeList, 0, EmptyType>::Type P0;
  typedef typename TLAtNonStrict<ArgTypeList, 1, EmptyType>::Type P1;
  typedef typename TLAtNonStrict<ArgTypeList, 2, EmptyType>::Type P2;
  typedef typename TLAtNonStrict<ArgTypeList, 3, EmptyType>::Type P3;
  typedef typename TLAtNonStrict<ArgTypeList, 4, EmptyType>::Type P4;
  typedef typename TLAtNonStrict<ArgTypeList, 5, EmptyType>::Type P5;
  typedef typename TLAtNonStrict<ArgTypeList, 6, EmptyType>::Type P6;
  typedef typename TLAtNonStrict<ArgTypeList, 7, EmptyType>::Type P7;
  typedef typename TLAtNonStrict<ArgTypeList, 8, EmptyType>::Type P8;
  typedef typename TLAtNonStrict<ArgTypeList, 9, EmptyType>::Type P9;
  typedef typename TLAtNonStrict<ArgTypeList, 10, EmptyType>::Type P10;
  typedef typename TLAtNonStrict<ArgTypeList, 11, EmptyType>::Type P11;
  typedef typename TLAtNonStrict<ArgTypeList, 12, EmptyType>::Type P12;
  typedef typename TLAtNonStrict<ArgTypeList, 13, EmptyType>::Type P13;
  typedef typename TLAtNonStrict<ArgTypeList, 14, EmptyType>::Type P14;

private:
  ObjPtr m_pObj;
  MemFnPtr m_pMemFn;

public:
  MemFnHandler(const ObjPtr& pObj, const MemFnPtr& pMemFn) : m_pObj(pObj), m_pMemFn(pMemFn) {}
  virtual ~MemFnHandler() {}
  virtual FnImpl<ResultType, ArgTypeList>* clone() { return new MemFnHandler(m_pObj, m_pMemFn); }

  inline ResultType operator()() { return ((*m_pObj).*m_pMemFn)(); }
  inline ResultType operator()(P0 p0) { return ((*m_pObj).*m_pMemFn)(p0); }
  inline ResultType operator()(P0 p0, P1 p1) { return ((*m_pObj).*m_pMemFn)(p0, p1); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2) { return ((*m_pObj).*m_pMemFn)(p0, p1, p2); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3) { return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4) { return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3, p4); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3, p4, p5); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3, p4, p5, p6); }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
    return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3, p4, p5, p6, p7);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
    return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3, p4, p5, p6, p7, p8);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) {
    return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10) {
    return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11) {
    return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11, P12 p12) {
    return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11, P12 p12, P13 p13) {
    return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13);
  }
  inline ResultType operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11, P12 p12, P13 p13, P14 p14) {
    return ((*m_pObj).*m_pMemFn)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14);
  }

};

/// <summary>
///   The functor class.
///   
/// </summary>
template <typename TRet, class TArgList>
class Fn {
public:
  typedef TRet ResultType;
  typedef TArgList ArgTypeList;
private:
  typedef typename TLAtNonStrict<TArgList, 0, EmptyType>::Type P0;
  typedef typename TLAtNonStrict<TArgList, 1, EmptyType>::Type P1;
  typedef typename TLAtNonStrict<TArgList, 2, EmptyType>::Type P2;
  typedef typename TLAtNonStrict<TArgList, 3, EmptyType>::Type P3;
  typedef typename TLAtNonStrict<TArgList, 4, EmptyType>::Type P4;
  typedef typename TLAtNonStrict<TArgList, 5, EmptyType>::Type P5;
  typedef typename TLAtNonStrict<TArgList, 6, EmptyType>::Type P6;
  typedef typename TLAtNonStrict<TArgList, 7, EmptyType>::Type P7;
  typedef typename TLAtNonStrict<TArgList, 8, EmptyType>::Type P8;
  typedef typename TLAtNonStrict<TArgList, 9, EmptyType>::Type P9;
  typedef typename TLAtNonStrict<TArgList, 10, EmptyType>::Type P10;
  typedef typename TLAtNonStrict<TArgList, 11, EmptyType>::Type P11;
  typedef typename TLAtNonStrict<TArgList, 12, EmptyType>::Type P12;
  typedef typename TLAtNonStrict<TArgList, 13, EmptyType>::Type P13;
  typedef typename TLAtNonStrict<TArgList, 14, EmptyType>::Type P14;

private:
  typedef FnImpl<TRet, TArgList> Impl;
  SinglePtr<Impl> m_impl;

public:

  /// <summary>
  ///   Constructor for simple functions and functors.
  /// </summary>
  template<class Fun>
  Fn(const Fun &fun) : m_impl(new FnHandler<Fn, Fun>(fun)) {}

  /// <summary>
  ///   Constructor for member functions.
  /// </summary>
  template<typename ObjPtr, typename MemFnPtr>
  Fn(const ObjPtr& pObj, const MemFnPtr& pMemFn) :
    m_impl(new MemFnHandler<Fn, ObjPtr, MemFnPtr>(pObj, pMemFn)) {}

  Fn(const Fn& source) : m_impl(source.m_impl.ptr()->clone()) {}

  Fn& operator=(const Fn& source) {
    if (&source != this) m_impl.reset(source.m_impl.ptr()->clone());
    return *this;
  }

  // for test purpose only - do not use it in real program!!!
  inline const Impl* impl() { return m_impl.ptr(); }

  inline TRet operator()() { return (*m_impl)(); }
  inline TRet operator()(P0 p0) { return (*m_impl)(p0); }
  inline TRet operator()(P0 p0, P1 p1) { return (*m_impl)(p0, p1); }
  inline TRet operator()(P0 p0, P1 p1, P2 p2) { return (*m_impl)(p0, p1, p2); }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3) { return (*m_impl)(p0, p1, p2, p3); }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4) { return (*m_impl)(p0, p1, p2, p3, p4); }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { return (*m_impl)(p0, p1, p2, p3, p4, p5); }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { return (*m_impl)(p0, p1, p2, p3, p4, p5, p6); }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
    return (*m_impl)(p0, p1, p2, p3, p4, p5, p6, p7);
  }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
    return (*m_impl)(p0, p1, p2, p3, p4, p5, p6, p7, p8);
  }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) {
    return (*m_impl)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
  }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10) {
    return (*m_impl)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
  }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11) {
    return (*m_impl)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
  }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11, P12 p12) {
    return (*m_impl)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12);
  }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11, P12 p12, P13 p13) {
    return (*m_impl)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13);
  }
  inline TRet operator()(P0 p0, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10,
      P11 p11, P12 p12, P13 p13, P14 p14) {
    return (*m_impl)(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14);
  }
};

  // end of namespace fm::base
  }
// end of namespace fm
}

#endif